package cn.com.surker.task;

import cn.com.surker.base.BaseEntity;
import cn.com.surker.enums.StateEnum;
import cn.com.surker.enums.production.invoice.InvoiceProcessEnum;
import cn.com.surker.handler.BCSStarter;
import cn.com.surker.lab.service.LabExpendBService;
import cn.com.surker.lab.vo.LabExpendVoB;
import cn.com.surker.production.entity.InvoiceForce;
import cn.com.surker.production.entity.ProductionIndentDispatch;
import cn.com.surker.production.service.ErpIndentDispatchService;
import cn.com.surker.production.service.ErpInvoiceForceService;
import cn.com.surker.production.service.ErpInvoiceService;
import cn.com.surker.redis.RedisUtils;
import cn.com.surker.util.DateUtil;
import cn.com.surker.workcon.service.DosageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.transaction.RollbackException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 生产中对接工控的定时任务
 *
 * @author luotao
 * @date 2024/9/27
 */
@Slf4j
@Configuration
@EnableScheduling
public class ProBcsTask {

	@Resource
	private RedisUtils redisUtils;

	@Autowired
	private BCSStarter bcsStarter;
	@Autowired
	private ErpIndentDispatchService erpDispatchService;
	@Autowired
	private LabExpendBService labExpendBService;
	@Resource
	private DosageService dosageService;
	@Autowired
	private ErpInvoiceService erpInvoiceService;

	@Autowired
	private ErpInvoiceForceService erpInvoiceForceService;

	@Value("${erp.datasource.erp.db}")
	private String dbCode;


	/**
	 * 查询等待生产是否开始生产的
	 */
	@Scheduled(cron = "0/30 * * * * ? ")
	public void startProIng() {
		//	查询工控机数据
		List<Object> mixObjects = redisUtils.listValues(BCSStarter.REDIS_BCS_DIS_INVOICE_KEY);
		log.info("执行同步程序");
		if (mixObjects != null && !mixObjects.isEmpty()) {
			for (int i = 0, s = mixObjects.size(); i < s; i++) {
				try {
					Object redisVal = mixObjects.get(i);
					//	任务单id
					Long dispatchId = Long.valueOf(redisVal.toString());
					//	查询派单信息
					ProductionIndentDispatch dispatch = erpDispatchService.getById(dispatchId);
					if (!BaseEntity.validateExist(dispatch)) {
						//	不存在
						continue;
					}
					log.info("重启查询单号:" + dispatch.getCode());
					Integer proStatus = dispatch.getProStatus();
					if (!InvoiceProcessEnum.QUERN_PRO.getCode().equals(proStatus)) {
						//	不为待接收状态
						continue;
					}
					//	查询派单
					bcsStarter.startProIng(dispatchId);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 1小时1次,查询数据库中的派单表中往工控机中派单,但是没有查询回来的数据
	 */
	// @Scheduled(cron = "* * 0/1 * * ?")
	public void syncDisDb() {
		String code = "";
		Long indentId = null;
		Long lineId = null;
		//	查询正在生产未同步的数据
		List<ProductionIndentDispatch> dispatchList = erpDispatchService.findList(code, indentId, lineId, InvoiceProcessEnum.QUERN_RECEIVE.getCode());
		if (dispatchList != null && dispatchList.size() > 0) {
			for (ProductionIndentDispatch dispatch : dispatchList) {
				Long dispatchId = dispatch.getId();
				//	存入缓存
				redisUtils.rightPush(BCSStarter.REDIS_BCS_DISPATCH_KEY, dispatchId.toString());
			}
		}
	}

	/**
	 * 同步发货单数据
	 */
	// @Scheduled(cron = "30 0/10 * * * ?")
	public void syncInvoice() {
		List<Object> mixObjects = redisUtils.listValues(BCSStarter.REDIS_BCS_DIS_INVOICE_KEY);
		if (mixObjects != null && !mixObjects.isEmpty()) {
			for (int i = 0, s = mixObjects.size(); i < s; i++) {
				try {
					Object redisVal = mixObjects.get(i);
					//	任务单id
					Long dispatchId = Long.valueOf(redisVal.toString());
					bcsStarter.startInvoice(dispatchId);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 1小数1次,查询未被生产的派单,即工控机接收,但是未删除也未生产的数据
	 */
	// @Scheduled(cron = "* * 0/1 * * ?")
	public void syncInvDb() {
		String code = "";
		Long indentId = null;
		Long lineId = null;
		//	查询正在生产未同步的数据
		List<ProductionIndentDispatch> dispatchList = erpDispatchService.findList(code, indentId, lineId, InvoiceProcessEnum.QUERN_PRO.getCode(), InvoiceProcessEnum.PRO.getCode());
		if (dispatchList != null && dispatchList.size() > 0) {
			for (ProductionIndentDispatch dispatch : dispatchList) {
				Long dispatchId = dispatch.getId();
				//	存入缓存
				redisUtils.rightPush(BCSStarter.REDIS_BCS_DIS_INVOICE_KEY, dispatchId.toString());
			}
		}
	}

	/**
	 * 同步一段时间内工控机生产的发货单
	 */
	@Scheduled(cron = "10 0/20 * * * ?")
	// @Scheduled(cron = "22 05 01 * * ?")
	public void syncCustomInv() {
		bcsStarter.syncControlInvoice();
	}

	/**
	 * 全量同步工控机消耗数据
	 */
	// @Scheduled(cron = "01 30 23 * * ?")
	@Scheduled(cron = "10 5/20 * * * ?")
	public void syncAllControl() {
		Date endDate = new Date();
		Date startDate = DateUtil.convertBeforeDayDate(endDate, 2);
		String startTime = DateUtil.convertString(startDate);
		String endTime = DateUtil.convertString(endDate);
		bcsStarter.syncAllControl(startTime, endTime);
		System.err.println("从备份数据匹配消耗完成");
	}

	/**
	 * 同步手动消耗
	 */
	// @Scheduled(cron = "* 30 0/4 * * ?")
	// @Scheduled(cron = "22 19 23 * * ?")
	public void syncManuale() {
		// Date endDate = new Date();
		//Date startDate = DateUtil.convertBeforeDayDate(endDate, 2);
		//String startTime = DateUtil.convertString(startDate);
		//String endTime = DateUtil.convertString(endDate);
		bcsStarter.convertManuale();
	}

	/**
	 * 根据手动消耗中的过量消耗,匹配出一张手动发货单
	 */
	// @Scheduled(cron = "01 10 03 * * ?")
	public void createHandInv() {
		//	先查询是否存在水泥消耗大于150的
		//	查询该记录前后5分钟石子等材料450的
		//	匹配该水泥消耗时间的之前且时间最接近的一车派单
		//	判定该派单的派单方量和生成方量是否存在差异
		//	如果存在差异,按照差异方量,生成一张手动创建的派单
		bcsStarter.createHandInv();
	}

	/**
	 * 重新匹配发货单缺失的消耗仓位
	 */
	@Scheduled(cron = "34 43 22 * * ?")
	public void syncInvoiceExpend() {
		Date endDate = new Date();
		Date startDate = DateUtil.convertBeforeDayDate(endDate, 30);
		String startTime = DateUtil.convertString(startDate);
		String endTime = DateUtil.convertString(endDate);
		bcsStarter.syncInvoiceStorage(null, startTime, endTime);
	}

	/**
	 * 从备份库同步工控消耗废弃不用
	 */
	@Deprecated
	public void syncBackStorage() {
		Date endDate = new Date();
		Date startDate = DateUtil.convertBeforeDayDate(endDate, 60);
		String startTime = DateUtil.convertString(startDate);
		String endTime = DateUtil.convertString(endDate);
		bcsStarter.syncBackStorage(null, startTime, endTime);
		System.err.println("从备份数据匹配消耗完成");
	}

	/**
	 * 查询erp中没有盘方量的发货单并补算
	 * 主要是用思路和sql
	 */
	// @Scheduled(cron = "01 45 18 * * ?")
	public void syncNoBatchInv() {
		String startTime = "2025-02-25 00:00:00";
		String endTime = "2025-05-25 00:00:00";
		bcsStarter.syncNoBatchInv(startTime, endTime);
		System.err.println("从备份数据匹配消耗完成");
	}

	/**
	 * 查询erp中没有的消耗,并从备份库中匹配
	 */
	// @Scheduled(cron = "01 12 09 * * ?")
	public void syncNoLab() {
		String startTime = "2025-01-25 00:00:00";
		String endTime = "2025-02-25 00:00:00";
		bcsStarter.syncNoLab(startTime, endTime);
		System.err.println("从备份数据匹配消耗完成");
	}

	/**
	 * 查询erp的盘方量中没有工控机盘id的数据
	 */
	// @Scheduled(cron = "01 06 11 * * ?")
	public void syncNoBatchNO() {
		String startTime = "2025-02-25 00:00:00";
		String endTime = "2025-03-25 00:00:00";
		bcsStarter.syncNoBatchNO(startTime, endTime);
	}

	/**
	 * 回写B库消耗数据到工控机
	 */
	// @Scheduled(cron = "10 2/10 * * * ?")
	 @Transactional(rollbackFor = RollbackException.class,propagation = Propagation.REQUIRED)
	public void writeBackB() {
		//	查询没有回写的数据
		List<LabExpendVoB> labExpendBList = labExpendBService.findNotWrite();
		if (labExpendBList == null || labExpendBList.isEmpty()) {
			return;
		}
		//	根据生产线分组
		Map<Long, List<LabExpendVoB>> lineMap = labExpendBList.stream().filter(e -> {
			if (e == null) {
				return false;
			}
			if (e.getLineId() == null) {
				return false;
			}
			return true;
		}).collect(Collectors.groupingBy(LabExpendVoB::getLineId));
		//	生产线
		Set<Long> lineIds = lineMap.keySet();
		//	插入成功的id
		List<Long> waitIds = new ArrayList<>();
		for (Long lineId : lineIds) {
			//	取出消耗数据
			List<LabExpendVoB> labExpendVoBS = lineMap.get(lineId);
			List<Long> doIds = dosageService.writeBackB(lineId, labExpendVoBS);
			if (doIds != null && doIds.size() > 0) {
				waitIds.addAll(doIds);
			}
		}
		//	更新回写状态
		labExpendBService.setUpWrite(waitIds);
		//	提交事务
		// dosageService.commitTranAll();
	}

	/**
	 * 处理强制完成的发货单数据
	 */
	@Scheduled(cron = "1 0 0/1 * * ?")
	public void invForce() {
		//	查询强制完成后,未处理的发货单
		List<InvoiceForce> forceList = erpInvoiceForceService.findNoComplete();
		if (forceList == null || forceList.isEmpty()) {
			return;
		}
		Date nowDate = new Date();
		for (int i = 0, s = forceList.size(); i < s; i++) {
			InvoiceForce invoiceForce = forceList.get(i);
			Long invoiceId = invoiceForce.getInvoiceId();
			if (invoiceId == null) {
				continue;
			}
			Double proStere = erpInvoiceService.queryProStere(dbCode, invoiceId);
			if (proStere != null && proStere > 0d) {
				//	已经存在数据了,进行更新
				invoiceForce.setComplete(StateEnum.DISABLED.getCode());
				erpInvoiceForceService.updateById(invoiceForce);
				continue;
			}
			//	查询消耗
			Long dispatchId = invoiceForce.getDispatchId();
			Long lineId = invoiceForce.getLineId();
			boolean syncWcData = bcsStarter.syncForceInvWcData(lineId, dispatchId);
			if (syncWcData) {
				//	同步材料
				bcsStarter.startMaterial(dispatchId);
				//	操作成功,修改强制刷新数据
				invoiceForce.setComplete(StateEnum.DISABLED.getCode());
				invoiceForce.setUpdateTime(nowDate);
				erpInvoiceForceService.updateById(invoiceForce);
			}
		}

	}

}
